
let {Quaternion,Vector3,Matrix4,Matrix3} = require('../math');

const _up = new Vector3(0,1,0);
const _pos = new Vector3();
const _zero = new Vector3();

const _vec = new Vector3();
const _matrix = new Matrix4();
const _maxtrix3 = new Matrix3();

const DefaultDir = new Vector3(0,0,-1);

class Transform{

    constructor(){
        this._position = new Vector3();
        this._scale = new Vector3(1,1,1);
        this._quat = new Quaternion();

        this._worldMatrix = new Matrix4();
        this._matrixDirty = false;
    }

    /**
     * 返回的是在  世界坐标系表示下的 dir
     * @param target
     * @return {Vector3}
     */
    getDir(target){
        return target.copy(DefaultDir).applyQuaternion(this._quat);
    }

    getWorldMatrix(){
        return this._worldMatrix;
    }

    /**
     * 手动更新
     * @return {Transform}
     */
    updateMatrix(){
        if (this._matrixDirty){
           this._worldMatrix.compose(this._position,this._quat,this._scale);
        }
        return this;
    }
    setPosition(x,y,z){
        this._position.set(x,y,z);
        this._matrixDirty = true;
        return this;
    }
    translate(vec3){
        this._position.add(vec3);
        this._matrixDirty = true;
    }
    getPosition(){
        return this._position;
    }
    setScale(x,y,z){
        this._scale.set(x,y,z);
        this._matrixDirty = true;
        return this;
    }


    /**
     *
     * @param q {Quaternion} 局部坐标系下的表示
     * @return {Transform}
     */
    rotate(q){
        this._quat.multiply(q);
        this._matrixDirty = true;
        return this;
    }

    /**
     *
     * @param newDir {Vector3}   newDir 是局部坐标系下的 dir
     * @return {Transform}
     */
    rotateTo(newDir){

        // 把 newDir 先变换到世界坐标系
        this.updateMatrix();
        let normalMatrix = _maxtrix3.getNormalMatrix(_matrix);
        let worldDir = _vec.copy(newDir).normalize().applyMatrix3(normalMatrix);
        this.rotateToWorldDir(worldDir);
        return this;
    }

    /**
     *
     * @param vec {Vector3}
     * @return {Transform}
     */
    translateOnWorld(vec){
        this.updateMatrix();
        _matrix.makeTranslation(vec.x,vec.y,vec.z);
        this._worldMatrix.premultiply(_matrix);

        // 需要进行分解
        this._worldMatrix.decompose(this._position,this._quat,this._scale);
        return this;
    }

    /**
     *
     * @param scale {Vector3}
     * @return {Transform}
     */
    scaleOnWorld(scale){
        this.updateMatrix();
        _matrix.makeTranslation(scale.x,scale.y,scale.z);
        this._worldMatrix.premultiply(_matrix);

        this._worldMatrix.decompose(this._position,this._quat,this._scale);
        return this;
    }

    /**
     *
     * @param q {Quaternion}  世界坐标系下的表示
     * @return {Transform}
     */
    rotateOnWorld(q){
        this.updateMatrix();
        _matrix.makeRotationFromQuaternion(q);
        this._worldMatrix.premultiply(_matrix);
        this._worldMatrix.decompose(this._position,this._quat,this._scale);
        return this;
    }

    /**
     * 旋转到 朝  dir 这方向.
     * 不会影响 position
     * @param worldDir {Vector3}  worldDir 是在世界坐标系下表示的方向
     * @return {Transform}
     */
    rotateToWorldDir(worldDir){
        // 根据dir 求 quat
        Transform.calQuatByDir(worldDir,this._quat);
        this._matrixDirty = true;
        return this;
    }

    /**
     * 根据 newDir计算一个旋转矩阵,用四元数表示 存入 target
     * @param newDir {Vector3}
     * @param target {Quaternion}
     * @return {Quaternion}
     */
    static calQuatByDir(newDir,target){
        let dir = _vec.copy(newDir).normalize();
        _pos.subVectors(_zero,dir);
        _matrix.lookAtInThreeJs(_pos,_zero,_up);
        return target.setFromRotationMatrix(_matrix);
    }
}

module.exports = Transform;



